﻿using System;

namespace MathService.Vectors
{
    public partial struct Vector3D
    {
        public void Inverse()
        {
            f_X = 1 / f_X;
            f_Y = 1 / f_Y;
            f_Z = 1 / f_Z;
        }

        public Vector3D GetInverse()
        {
            return new Vector3D(1 / f_X, 1 / f_Y, 1 / f_Z);
        }

        private void SetValue(double r, double thetta, double phi)
        {
            f_Z = r * Math.Sin(thetta);
            var lv_r = r * Math.Cos(thetta);
            f_X = lv_r * Math.Cos(phi);
            f_Y = lv_r * Math.Sin(phi);
        }

        private void SetValue(double r, SpaceAngle angle)
        {
            angle = angle.InRad;
            SetValue(r, angle.Thetta, angle.Phi);
        }

        /// <summary>Скалярное произведение векторов</summary>
        /// <param name="Vector">Вектор, на который домножается текущий вектор</param>
        /// <returns>Число, равное скалярному произведению векторов</returns>
        public double Product_Scalar(Vector3D Vector)
        {
            return X * Vector.X + Y * Vector.Y + Z * Vector.Z;
        }

        /// <summary>Смешанное произведение трёх векторов</summary>
        /// <param name="A">Первый вектор произведения</param>
        /// <param name="B">Второй вектор произведения</param>
        /// <param name="C">Третий вектор произведения</param>
        /// <returns>Число, равное смешанному произведения векторов</returns>
        public static double Product_Mixed(Vector3D A, Vector3D B, Vector3D C)
        {
            return
                (+1 * A.f_X * (B.f_Y * C.f_Z - B.f_Z * C.f_Y)) +
                (-1 * A.f_Y * (B.f_X * C.f_Z - B.f_Z * C.f_X)) +
                (+1 * A.f_Z * (B.f_X * C.f_Y - B.f_Y * C.f_X));
        }

        /// <summary>Векторное произведение векторов</summary>
        /// <param name="Vector">Вектор, на который домножается исходный вектор</param>
        /// <returns>Вектор, равный векторному произведению векторов</returns>
        public Vector3D Product_Vector(Vector3D Vector)
        {
            /*
             * A = {Xa, Ya, Za}
             * B = {Xb, Yb, Zb}
             *         | i  j  k  |   {Ya * Zb - Za * Yb}   {Xc}
             * A * B = | Xa Ya Za | = {Za * Xb - Xa * Zb} = {Yc} = C
             *         | Xb Yb Zb |   {Xa * Yb - Ya * Xb}   {Zc}
             * C = {Xc, Yc, Zc}
             */

            var lv_A = this;
            var lv_B = Vector;
            return new Vector3D
                (
                    lv_A.f_Y * lv_B.f_Z - lv_A.f_Z * lv_B.f_Y, // X
                    lv_A.f_Z * lv_B.f_X - lv_A.f_X * lv_B.f_Z, // Y
                    lv_A.f_X * lv_B.f_Y - lv_A.f_Y * lv_B.f_X  // Z
                );
        }

        /// <summary>Угол между векторами</summary>
        /// <param name="Vector">Вектор, к которорому вычисляется угол</param>
        /// <returns>Пространственный угол между векторами</returns>
        public SpaceAngle GetAngle(Vector3D Vector)
        {
            var lv_Angle1 = Angle;
            var lv_Angle2 = Vector.Angle;
            return lv_Angle1 - lv_Angle2;
        }

        /// <summary>Проекция на вектор</summary>
        /// <param name="Vector">Вектор, НА который производится проекция</param>
        /// <returns>Проекция на вектор</returns>
        public double GetProjectionTo(Vector3D Vector) { return Product_Scalar(Vector) / Vector.R; }

        /// <summary>Проекция на наравление</summary>
        /// <param name="Direction">Направление, на которое проектируется вектор</param>
        /// <returns>Проекция вектора на направление</returns>
        public double GetProjectionTo(SpaceAngle Direction)
        {
            Direction = Direction.InRad;
            var thetta = Direction.Thetta;
            var phi = Direction.Phi;
            return Math.Cos(thetta) * (f_X * Math.Cos(phi) + f_Y * Math.Sin(phi)) + f_Z * Math.Sin(thetta);
        }
    }
}
